package com.renovate.portal.util;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;

import android.util.Log;

public class CMDProcessor {

	public class CommandResult {
		public final String stdout;
		public final String stderr;
		public final Integer exit_value;

		CommandResult(final Integer exit_value_in) {
			this(exit_value_in, null, null);
		}

		CommandResult(final Integer exit_value_in, final String stdout_in,
				final String stderr_in) {
			exit_value = exit_value_in;
			stdout = stdout_in;
			stderr = stderr_in;
		}

		public boolean success() {
			return exit_value != null && exit_value == 0;
		}
	}

	public class SH {
		private String SHELL = "sh";

		public SH(final String SHELL_in) {
			SHELL = SHELL_in;
		}

		@SuppressWarnings("deprecation")
		private String getStreamLines(final InputStream is) {
			String out = null;
			StringBuffer buffer = null;
			final DataInputStream dis = new DataInputStream(is);

			try {
				if (dis.available() > 0) {
					buffer = new StringBuffer(dis.readLine());
					while (dis.available() > 0) {
						buffer.append("\n").append(dis.readLine());
					}
				}
				dis.close();
			} catch (final Exception ex) {
				Log.e("Renovate", ex.getMessage());
			}
			if (buffer != null) {
				out = buffer.toString();
			}
			return out;
		}

		public Process run(final String s) {
			Process process = null;
			try {
				process = Runtime.getRuntime().exec(SHELL);
				final DataOutputStream toProcess = new DataOutputStream(
						process.getOutputStream());
				toProcess.writeBytes("exec " + s + "\n");
				toProcess.flush();
			} catch (final Exception e) {
				Log.e("Renovate",
						"Exception while trying to run: '" + s + "' "
								+ e.getMessage());
				process = null;
			}
			return process;
		}

		public CommandResult runWaitFor(final String s) {
			final Process process = run(s);
			Integer exit_value = null;
			String stdout = null;
			String stderr = null;
			if (process != null) {
				try {
					exit_value = process.waitFor();

					stdout = getStreamLines(process.getInputStream());
					stderr = getStreamLines(process.getErrorStream());

				} catch (final InterruptedException e) {
					Log.e("Renovate", "runWaitFor " + e.toString());
				} catch (final NullPointerException e) {
					Log.e("Renovate", "runWaitFor " + e.toString());
				}
			}
			return new CommandResult(exit_value, stdout, stderr);
		}
	}

	public static com.renovate.portal.util.CommandResult runShellCommand(String cmd) {
		ChildProcess proc = startShellCommand(cmd);
		proc.waitFinished();
		return proc.getResult();
	}

	public static com.renovate.portal.util.CommandResult runSuCommand(String cmd) {
		ChildProcess proc = startSuCommand(cmd);
		proc.waitFinished();
		return proc.getResult();
	}

	public static com.renovate.portal.util.CommandResult runSysCmd(
			String[] cmdarray, String childStdin) {
		ChildProcess proc = startSysCmd(cmdarray, childStdin);
		proc.waitFinished();
		return proc.getResult();
	}

	public static ChildProcess startShellCommand(String cmd) {
		String[] cmdarray = new String[3];
		cmdarray[0] = "sh";
		cmdarray[1] = "-c";
		cmdarray[2] = cmd;
		return startSysCmd(cmdarray, null);
	}

	public static ChildProcess startSuCommand(String cmd) {
		String[] cmdarray = new String[3];
		cmdarray[0] = "su";
		cmdarray[1] = "-c";
		cmdarray[2] = cmd;
		return startSysCmd(cmdarray, null);
	}

	public static ChildProcess startSysCmd(String[] cmdarray, String childStdin) {
		return new ChildProcess(cmdarray, childStdin);
	}

	private Boolean can_su;

	public SH sh;

	public SH su;

	public CMDProcessor() {
		sh = new SH("sh");
		su = new SH("su");
	}

	public boolean canSU() {
		return canSU(false);
	}

	public boolean canSU(final boolean force_check) {
		if (can_su == null || force_check) {
			final CommandResult r = su.runWaitFor("id");
			final StringBuilder out = new StringBuilder();

			if (r.stdout != null) {
				out.append(r.stdout).append(" ; ");
			}
			if (r.stderr != null) {
				out.append(r.stderr);
			}

			Log.d("Renovate", "canSU() su[" + r.exit_value + "]: " + out);
			can_su = r.success();
		}
		return can_su;
	}

	public SH suOrSH() {
		return canSU() ? su : sh;
	}
}
